#pragma once

// Copyright (c) 2010 Manuel Peinado Gallego <manuel.peinado@gmail.com>
// Distributed under the MIT license

// NodeManager.h : interface of the NodeManager class
//

#include "Primitive.h"
#include "Node.h"
#include "NodeEvent.h"
#include "tree.h"
class View3d;
class World;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class NodeManager : boost::noncopyable
{
public:

    NodeManager(World* m_world);
    ~NodeManager();
    
    NodeTree& getNodes() { return m_nodes; }
    const NodeTree& getNodes() const { return m_nodes; }

	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    NodeIterator nodesBegin() { return m_nodes.begin(); }
    NodeIterator nodesEnd() { return m_nodes.end(); }

    ConstNodeIterator nodesBegin() const { return m_nodes.begin(); }
    ConstNodeIterator nodesEnd() const { return m_nodes.end(); }

	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    template<class Iter>
    Iter nextSibling(Iter it) const { return m_nodes.next_sibling(it); }

    World* getWorld() const { return m_world; }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Serialization of a single node (this should probably be in 
    // a factory class
    // These operations can't be done at the node level because we must
    // also write/read a node's type and a node's parents, and those
    // can only be handler at a higher level

    void writeNode(std::wostream& os, ref<const Node> node) const;
    void readNode(std::wistream& is);

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    // Management of the block tree

    // Append a whole tree
    void appendTree(const NodeTree& other);

    // Append a range of sibling nodes, together with their children
    void appendSiblings(NodeSiblingIterator begin, NodeSiblingIterator end);

    // Appends a node and all its children
    void appendBranch(NodeIterator root);

    // Append node to parent
    void append(Node* parent, ref<Node> node);

    // Append top-level node
    void append(ref<Node> node);

    // Makes "newParent" the parent of "block". If "newParent" is a descendent 
    // of "block", nothing is done
    void reparent(Node* node, Node* newParent);

    // Removes only this node, which means that its parent becomes the 
    // parent of the node's children
    void remove(Node* node);

	// Removes a node and its subtree
    void removeBranch(Node* node);

	// Removes the children of a node
    void removeChildren(Node* node);

    //void replaceShape(const Node & block, ref<Shape> shape);
    //void translateBlock(const Node & from, const Node & to);

    // Removes all blocks
    void clear(); 
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    // Creates a very simple scene, useful for debuggin purposes
    
    void createDummyScene(); 

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    void clearListeners();
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    Node* getNodeByName(const std::wstring& name) const;

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    bool hasName(const std::wstring& name) const;
    std::wstring generateNameFromPrefix(const std::wstring& prefix) const;

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    
    // Nodes belonging to this manager should call this function when their
    // appearance changes (i.e., when they need to be repainted)
    void notifyNodePropertyChanged(Node*, NodeEvent::Property); 

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    void addNodeListener(NodeListener* listener);
    void removeNodeListener(NodeListener* listener);

private:

    // We use set<> to avoid duplicates
    typedef std::set<NodeListener*>::iterator ListenerIt;
    std::set<NodeListener *> m_listeners;

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

	NodeTree m_nodes;
    World* m_world;
};

